#include "skilltablemodel.h"


#include <dtwentymodel.h>
#include <characterclass.h>
#include <skill.h>


#include <QDebug>
#include <QTimer>
#include <QStringList>

SkillTableModel::SkillTableModel(QObject *parent) :
    QAbstractTableModel(parent)
{
}

void SkillTableModel::setCampaign(Campaign *campaign)
{
    if (m_campaign.data() == campaign)
    {
        return;
    }

    beginResetModel();
    m_skills = 0;
    m_characterClasses = 0;
    m_campaign = campaign;

    if (!m_campaign.isNull())
    {
        m_skills = m_campaign->findChild<Skills*>(QString(), Qt::FindDirectChildrenOnly);
        m_characterClasses = m_campaign->findChild<CharacterClasses*>(QString(), Qt::FindDirectChildrenOnly);
    }
    endResetModel();
}

int SkillTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    if (!ready())
    {
        return 0;
    }


    QList<Skill*> skillList = m_skills->findChildren<Skill*>(QString(), Qt::FindDirectChildrenOnly);
    return skillList.count();
}


int SkillTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    if (!ready())
    {
        return 0;
    }

    QList<CharacterClass*> characterClassList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    return characterClassList.count() + 1;
}

QVariant SkillTableModel::data(const QModelIndex &index, int role) const
{
    if (!ready() || !index.isValid())
    {
        return QVariant();
    }

    if (index.column() == 0)
    {
        if (role != Qt::DisplayRole && role != Qt::EditRole)
        {
            return QVariant();
        }

        QList<Skill*> skillList = m_skills->findChildren<Skill*>(QString(), Qt::FindDirectChildrenOnly);
        if (index.row() < 0 || index.row() >= skillList.count())
        {
            return tr("[Invalid Row]");
        }

        return skillList.at(index.row())->name();
    }

    if (role != Qt::CheckStateRole)
    {
        return QVariant();
    }


    QModelIndex skillIndex = index.sibling(index.row(), 0);

    if (!skillIndex.isValid())
    {
        qDebug() << Q_FUNC_INFO << "Skill Source is invalid";
        return QVariant();
    }

    QList<CharacterClass*> characterClassList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    int at = index.column()-1;

    if (at < 0 || at >= characterClassList.count())
    {
        return tr("[Invalid Column]");
    }

    CharacterClass* characterClass = characterClassList.at(at);
    if (!characterClass)
    {
        qDebug() << Q_FUNC_INFO << "Class Pointer is invalid";
        return QVariant();
    }

    foreach (Skill* skill, characterClass->findChildren<Skill*>())
    {
        if (skill->name() == skillIndex.data().toString())
        {
            return Qt::Checked;
        }
    }

    return Qt::Unchecked;

}

QVariant SkillTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (!ready())
    {
        return QVariant();
    }

    if (orientation == Qt::Vertical)
    {
        return QAbstractTableModel::headerData(section, orientation, role);
    }

    if (role != Qt::DisplayRole) // && role != Qt::ToolTipRole && role != Qt::StatusTipRole)
    {
        return QAbstractTableModel::headerData(section, orientation, role);
    }

    if (section == 0)
    {
        return tr("Skill");
    }

    int at = section-1;

    QList<CharacterClass*> characterClassList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    if (at < 0 || at >= characterClassList.count())
    {
        return tr("[Invalid Section]");
    }

    CharacterClass* characterClass = characterClassList.at(at);
    if (!characterClass)
    {
        return tr("[Invalid data]");
    }

    Skills* skills = characterClass->findChild<Skills*>(QString(), Qt::FindDirectChildrenOnly);
    if (!skills)
    {
        return characterClass->abbreviation();
    }

    QList<const Skill*> skillList = skills->findChildren<const Skill*>(QString(), Qt::FindDirectChildrenOnly);
    return QString("%1\n(%2)").arg(characterClass->abbreviation()).arg(skillList.count());


}

bool SkillTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!ready() || !index.isValid())
    {
        return false;
    }

    QList<Skill*> skillList = m_skills->findChildren<Skill*>(QString(), Qt::FindDirectChildrenOnly);
    if (index.row() < 0 || index.row() >= skillList.count())
    {
        return false;
    }

    Skill* skill = skillList.at(index.row());
    if (!skill)
    {
        return false;
    }

    if (index.column() == 0)
    {
        if (role != Qt::EditRole) return false;

        skill->setName(value.toString());
        emit dataChanged(index, index);
        return true;
    }

    if (role != Qt::CheckStateRole)
    {
        qDebug() << "class skill edit: not check state role";

        return false;
    }

    int at = index.column()-1;

    QList<CharacterClass*> characterClassList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    if (at < 0 || at >= characterClassList.count())
    {
        return false;
    }

    CharacterClass* characterClass = characterClassList.at(at);

    Skills* classSkills = characterClass->findChild<Skills*>(QString(), Qt::FindDirectChildrenOnly);
    QList<Skill*> classSkillList = classSkills->findChildren<Skill*>(QString(), Qt::FindDirectChildrenOnly);

    foreach (Skill* classSkill, classSkillList)
    {
        if (classSkill->name() != skill->name())
        {
            continue;
        }

        if (value.toInt() == Qt::Checked)
        {
            qDebug() << "Failed to remove class skill, value is 'checked'";
            return false;
        }

        classSkill->setParent(0);
        classSkill->deleteLater();

        emit dataChanged(index, index);
//        emit headerDataChanged(Qt::Horizontal, index.column(), index.column());

        return true;
    }

    if (value.toInt() == Qt::Unchecked)
    {
        return false;
    }

//    qDebug() << "Adding class skill" << characterClass->name() << skillSource.data().toString();

    Skill* classSkill = qobject_cast<Skill*>(classSkills->newChild());
    classSkill->setReferenceItem(skill);

    emit dataChanged(index, index);
//    emit headerDataChanged(Qt::Horizontal, index.column(), index.column());

    return true;
}

bool SkillTableModel::insertRows(int row, int count, const QModelIndex &parent)
{
    Q_UNUSED(count)

    if (!ready() || parent.isValid())
    {
        return false;
    }

    beginInsertRows(parent, row, row);
    m_skills->newChild(tr("New Skill"));
    endInsertRows();
    return true;
}

bool SkillTableModel::removeRows(int row, int count, const QModelIndex &parent)
{
    Q_UNUSED(count)

    if (!ready() || parent.isValid())
    {
        return false;
    }

    QList<Skill*> skillList = m_skills->findChildren<Skill*>(QString(), Qt::FindDirectChildrenOnly);
    if (row < 0 || row >= skillList.count())
    {
        return false;
    }

    beginRemoveRows(parent, row, row);
    Skill* skill = skillList.at(row);
    skill->setParent(0);
    skill->deleteLater();
    endRemoveRows();
    return true;
}

Qt::ItemFlags SkillTableModel::flags(const QModelIndex &index) const
{
    if (!ready() || !index.isValid())
    {
        qDebug() << Q_FUNC_INFO << "Invalid index";
        return QAbstractItemModel::flags(index);
    }

    if (index.column() == 0)
    {
        return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
    }

    return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
}

bool SkillTableModel::ready() const
{
    return (!m_campaign.isNull() && !m_characterClasses.isNull() && !m_skills.isNull());
}

void SkillTableModel::revert()
{
    qDebug() << Q_FUNC_INFO;

    emit layoutAboutToBeChanged();
    emit layoutChanged();
}


